﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

namespace AdferInternals
{
    public static class BitmapHelper
    {
        public static int[][] GetMatrix(Bitmap bitmap)
        {
            var result = new int[bitmap.Width][];

            for(var i = 0; i < bitmap.Width; ++i)
            {
                result[i] = new int[bitmap.Height];
                for(var j = 0; j < bitmap.Height; ++j)
                {
                    result[i][j] = bitmap.GetPixel(i, j).ToArgb();
                }
            }

            return result;
        }

        public static Bitmap GetBitmap(int[][] matrix)
        {
            var result = new Bitmap(matrix.Length, matrix[0].Length);

            for (var i = 0; i < matrix.Length; ++i)
            {
                for (var j = 0; j < matrix[i].Length; ++j)
                {
                    result.SetPixel(i, j, Color.FromArgb(matrix[i][j]));
                }
            }

            return result;
        }

        public static byte[][] GetAlphaMatrix(Bitmap bitmap)
        {
            var result = new byte[bitmap.Width][];

            for (var i = 0; i < bitmap.Width; ++i)
            {
                result[i] = new byte[bitmap.Height];
                for (var j = 0; j < bitmap.Height; ++j)
                {
                    result[i][j] = bitmap.GetPixel(i, j).A;
                }
            }

            return result;
        }

        public static byte[][] GetRedMatrix(Bitmap bitmap)
        {
            return GetBitmapRed(bitmap);
        }

        public static byte[][] GetGreenMatrix(Bitmap bitmap)
        {
            return GetBitmapGreen(bitmap);
        }

        public static byte[][] GetBlueMatrix(Bitmap bitmap)
        {
            return GetBitmapBlue(bitmap);
        }

        // Projection to a specific color.
        public static byte[][] GetMatrixFromColor(Bitmap bitmap, Color color)
        {
            // AARRGGBB

            var redMatrix = GetBitmapRed(bitmap);
            var greenMatrix = GetBitmapGreen(bitmap);
            var blueMatrix = GetBitmapBlue(bitmap);

            throw new NotImplementedException();
        }

        public static Bitmap GetBitmapFromAlpha(byte[][] matrix, Color baseColor)
        {
            var result = new Bitmap(matrix.Length, matrix[0].Length);

            for (var i = 0; i < matrix.Length; ++i)
            {
                for (var j = 0; j < matrix[i].Length; ++j)
                {
                    result.SetPixel(i, j, Color.FromArgb(matrix[i][j], baseColor));
                }
            }

            return result;
        }

        public static Bitmap GetBitmapFromRed(byte[][] matrix)
        {
            var result = new Bitmap(matrix.Length, matrix[0].Length);

            //for (var i = 0; i < matrix.Length; ++i)
            //{
            //    for (var j = 0; j < matrix[i].Length; ++j)
            //    {
            //        result.SetPixel(i, j, Color.FromArgb(255, matrix[i][j], 0, 0));
            //    }
            //}

            SetBitmapRed(result, matrix);

            return result;
        }

        public static Bitmap GetBitmapFromGreen(byte[][] matrix)
        {
            var result = new Bitmap(matrix.Length, matrix[0].Length);

            //for (var i = 0; i < matrix.Length; ++i)
            //{
            //    for (var j = 0; j < matrix[i].Length; ++j)
            //    {
            //        result.SetPixel(i, j, Color.FromArgb(255, 0, matrix[i][j], 0));
            //    }
            //}

            SetBitmapGreen(result, matrix);

            return result;
        }

        public static Bitmap GetBitmapFromBlue(byte[][] matrix)
        {
            var result = new Bitmap(matrix.Length, matrix[0].Length);

            //for (var i = 0; i < matrix.Length; ++i)
            //{
            //    for (var j = 0; j < matrix[i].Length; ++j)
            //    {
            //        result.SetPixel(i, j, Color.FromArgb(255, 0, 0, matrix[i][j]));
            //    }
            //}

            SetBitmapBlue(result, matrix);

            return result;
        }

        // Fast Setters.

        private static void SetBitmapRed(Bitmap bitmap, IList<byte[]> redMatrix)
        {
            var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
            var stride = data.Stride;

            unsafe
            {
                var ptr = (byte*)data.Scan0;

                for (var i = 0; i < redMatrix.Count; ++i)
                {
                    for (var j = 0; j < redMatrix[0].Length; ++j)
                    {
                        ptr[(i*3) + j*stride] = 0; // B
                        ptr[(i*3) + j*stride + 1] = 0; // G
                        ptr[(i*3) + j*stride + 2] = redMatrix[i][j]; // R
                    }
                }
            }

            bitmap.UnlockBits(data);
        }

        private static void SetBitmapGreen(Bitmap bitmap, IList<byte[]> greenMatrix)
        {
            var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
            var stride = data.Stride;

            unsafe
            {
                var ptr = (byte*)data.Scan0;

                for (var i = 0; i < greenMatrix.Count; ++i)
                {
                    for (var j = 0; j < greenMatrix[0].Length; ++j)
                    {
                        ptr[(i * 3) + j * stride] = 0; // B
                        ptr[(i * 3) + j * stride + 1] = greenMatrix[i][j]; // G
                        ptr[(i * 3) + j * stride + 2] = 0; // R
                    }
                }
            }

            bitmap.UnlockBits(data);
        }

        private static void SetBitmapBlue(Bitmap bitmap, IList<byte[]> blueMatrix)
        {
            var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
            var stride = data.Stride;

            unsafe
            {
                var ptr = (byte*)data.Scan0;

                for (var i = 0; i < blueMatrix.Count; ++i)
                {
                    for (var j = 0; j < blueMatrix[0].Length; ++j)
                    {
                        ptr[(i * 3) + j * stride] = blueMatrix[i][j]; // B
                        ptr[(i * 3) + j * stride + 1] = 0; // G
                        ptr[(i * 3) + j * stride + 2] = 0; // R
                    }
                }
            }

            bitmap.UnlockBits(data);
        }

        // Fast Getters.

        private static byte[][] GetBitmapRed(Bitmap bitmap)
        {
            var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            var stride = data.Stride;
            var redMatrix = new byte[bitmap.Width][];

            unsafe
            {
                var ptr = (byte*)data.Scan0;

                for (var i = 0; i < bitmap.Width; ++i)
                {
                    redMatrix[i] = new byte[bitmap.Height];
                    for (var j = 0; j < bitmap.Height; ++j)
                    {
                        redMatrix[i][j] = ptr[(i*3) + j*stride + 2];
                    }
                }
            }

            bitmap.UnlockBits(data);

            return redMatrix;
        }

        private static byte[][] GetBitmapGreen(Bitmap bitmap)
        {
            var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            var stride = data.Stride;
            var greenMatrix = new byte[bitmap.Width][];

            unsafe
            {
                var ptr = (byte*)data.Scan0;

                for (var i = 0; i < bitmap.Width; ++i)
                {
                    greenMatrix[i] = new byte[bitmap.Height];
                    for (var j = 0; j < bitmap.Height; ++j)
                    {
                        greenMatrix[i][j] = ptr[(i*3) + j*stride + 1];
                    }
                }
            }

            bitmap.UnlockBits(data);

            return greenMatrix;
        }

        private static byte[][] GetBitmapBlue(Bitmap bitmap)
        {
            var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            var stride = data.Stride;
            var blueMatrix = new byte[bitmap.Width][];

            unsafe
            {
                var ptr = (byte*)data.Scan0;

                for (var i = 0; i < bitmap.Width; ++i)
                {
                    blueMatrix[i] = new byte[bitmap.Height];
                    for (var j = 0; j < bitmap.Height; ++j)
                    {
                        blueMatrix[i][j] = ptr[(i*3) + j*stride];
                    }
                }
            }

            bitmap.UnlockBits(data);

            return blueMatrix;
        }

        //private static byte[][] GetBitmapColor(Bitmap bitmap, Color color)
        //{
        //    var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        //    var stride = data.Stride;
        //    var blueMatrix = new byte[bitmap.Width][];

        //    unsafe
        //    {
        //        var ptr = (byte*)data.Scan0;

        //        for (var i = 0; i < bitmap.Width; ++i)
        //        {
        //            blueMatrix[i] = new byte[bitmap.Height];
        //            for (var j = 0; j < bitmap.Height; ++j)
        //            {
        //                blueMatrix[i][j] = ptr[(i * 3) + j * stride];
        //            }
        //        }
        //    }

        //    bitmap.UnlockBits(data);

        //    return blueMatrix;
        //}
    }
}
